//
// Created by wujehy on 2020/7/7.
//

#include <cstring>
#include <iostream>
#include "MySQLCpp/Statement.h"
#include "mysql/mysql.h"
#include "MySQLCpp/DataBase.h"

#define MYSQL_BIND_BUFFER_LENGTH 255

using namespace GeeJoan::MySQL;

void Statement::bind(int index, int &idata, enum_field_types type)
{
    if (this->m_psize == 0)
    {
        return;
    }
    if (type == MYSQL_TYPE_LONG)
    {
        bind_params[index].buffer_type = type;
        bind_params[index].buffer = (char *) &idata;
        bind_params[index].is_null = 0;    // 是否为null
        bind_params[index].length = 0;        // 只有字符串时才有效
    }
}

void Statement::bind(int index, int64_t &idata, enum_field_types type)
{
    if (this->m_psize == 0)
    {
        return;
    }
    if (type == MYSQL_TYPE_LONGLONG)
    {
        bind_params[index].buffer_type = type;
        bind_params[index].buffer = (char *) &idata;
        bind_params[index].is_null = 0;    // 是否为null
        bind_params[index].length = 0;        // 只有字符串时才有效
    }
}

void Statement::bind(int index, const std::string &stringdata, enum_field_types type)
{
    if (this->m_psize == 0)
    {
        return;
    }

    if (type == MYSQL_TYPE_STRING || type == MYSQL_TYPE_VAR_STRING)
    {
        bind_params[index].buffer_type = type;
        bind_params[index].buffer = (char *) stringdata.c_str();
        bind_params[index].buffer_length = MYSQL_BIND_BUFFER_LENGTH;    // str最大长度
        bind_params[index].is_null = 0;
        bind_length[index] = stringdata.length();
//        unsigned long str_length =stringdata.size();
        bind_params[index].length = &bind_length[index];
    }
}

void Statement::bind(int index, const char *str, enum_field_types type)
{
    if (this->m_psize == 0)
    {
        return;
    }
    if (type == MYSQL_TYPE_STRING || type == MYSQL_TYPE_VAR_STRING)
    {
        bind_params[index].buffer_type = type;
        bind_params[index].buffer = (char *) str;
        // TODO
        bind_params[index].buffer_length = MYSQL_BIND_BUFFER_LENGTH;    // str最大长度
        bind_length[index] = strlen( str );
        bind_params[index].is_null = 0;
        bind_params[index].length = &bind_length[index];
    }
}

void Statement::bind(int index, float &fdata, enum_field_types type)
{
    if (this->m_psize == 0)
    {
        return;
    }
    if (type == MYSQL_TYPE_FLOAT)
    {
        bind_params[index].buffer_type = type;
        bind_params[index].buffer = (char *) &fdata;
        bind_params[index].is_null = 0;    // 是否为null
        bind_params[index].length = 0;        // 只有字符串时才有效

    }
}

void Statement::bind(int index, double &fdata, enum_field_types type)
{
    if (this->m_psize == 0)
    {
        return;
    }
    if (type == MYSQL_TYPE_DOUBLE)
    {
        bind_params[index].buffer_type = type;
        bind_params[index].buffer = (char *) &fdata;
        bind_params[index].is_null = 0;    // 是否为null
        bind_params[index].length = 0;        // 只有字符串时才有效
    }
}

void Statement::result_size(int size)
{

    if (bind_result != nullptr)
    {
        delete[]bind_result;
    }
    bind_result = new MYSQL_BIND[size];
}

void Statement::result_bind(int index, void *buffer, int buffer_length, enum_field_types type)
{
    if (bind_result == nullptr)
    {
        throw Exception( "The query size is not initialized , Call result_size() method setting ", -1 );
    }
    bind_result[index].buffer_type = type;
    bind_result[index].buffer = (char *) buffer;
    bind_result[index].is_null = 0;    // 是否为null
    bind_result[index].length = 0;        // 只有字符串时才有效
    bind_result[index].buffer_length = buffer_length;        // 只有字符串时才有效
}

int Statement::exec()
{
    stmt = mysql_stmt_init( hander->getHander());
    if (mysql_stmt_prepare( stmt, sql_str.c_str(), sql_str.length()))
    {
        throw Exception( hander->getHander());
    }

    int param_count = mysql_stmt_param_count( stmt );
    if (param_count != m_psize)
    {
        throw Exception( hander->getHander());
    }
    // 绑定参数
    int iRet = 0;
    if (m_psize > 0)
    {
        iRet = mysql_stmt_bind_param( stmt, bind_params );
        if (iRet != 0)
        {
            throw Exception( hander->getHander());
        }
    }

    iRet = mysql_stmt_execute( stmt );
    if (iRet != 0)
    {
        throw Exception( hander->getHander());
    }

    int affected_rows = mysql_stmt_affected_rows( stmt );  // 获取受影响的行信息
    if (stmt != nullptr)
    {
        mysql_stmt_close( stmt );
        stmt = nullptr;
    }
    return affected_rows;
}

Statement::Statement(DataBase *hander, const std::string &sql, int size) : hander( hander ), sql_str( sql ),
                                                                           m_psize( size )
{

    if (size > 0)
    {
        bind_length = new unsigned long[size];
        bind_is_null = new bool[size];
        bind_params = new MYSQL_BIND[size];
    }
}

Statement::Statement(DataBase *hander, const char *sql, int size) : hander( hander ), sql_str( sql ), m_psize( size )
{

    if (bind_params == nullptr)
    {
        bind_length = new unsigned long[size];
        bind_params = new MYSQL_BIND[size];
    }
}

Statement::~Statement()
{
    if (bind_params != nullptr)
    {
        delete[] bind_params;
    }
    if (bind_length != nullptr)
    {
        delete[] bind_length;
    }
    if (bind_is_null != nullptr)
    {
        delete[] bind_is_null;
    }
    if (stmt != nullptr)
    {
        mysql_stmt_close( stmt );
        stmt = nullptr;
    }

}

void Statement::reset()
{
    if (stmt != nullptr)
    {
        mysql_stmt_close( stmt );
        stmt = nullptr;
    }
}

bool Statement::Next()
{

    if (mysql_stmt_fetch( stmt ) == 0)
    {
        return true;
    } else
    {
        return false;
    }
//    if (current_column < colume_count)
//    {
//        m_currnet_row = mysql_fetch_row( prepare_meta_result);
//        return true;
//    }
//    return false;
}

int Statement::getRowCount() const
{
    return row_count;
}

int Statement::query()
{
    stmt = mysql_stmt_init( hander->getHander());
    if (mysql_stmt_prepare( stmt, sql_str.c_str(), sql_str.length()))
    {
        throw Exception( hander->getHander());
    }

    int param_count = mysql_stmt_param_count( stmt );
    if (param_count != m_psize)
    {
        throw Exception( hander->getHander());
    }
    // 绑定参数
    int iRet = 0;
    if (m_psize > 0)
    {
        iRet = mysql_stmt_bind_param( stmt, bind_params );
        if (iRet != 0)
        {
            throw Exception( hander->getHander());
        }
    }
    //
    // 获取结果集元信息
    prepare_meta_result = mysql_stmt_result_metadata( stmt );
    if (!prepare_meta_result)
    {
        throw Exception( hander->getHander());
    }
    // 获取查询中的总列数
    MYSQL_FIELD *field = nullptr;
    row_count = mysql_num_fields( prepare_meta_result );  //返回字段个数
    m_fields.clear();
    for (int i = 0; i < row_count; i++)
    {
        field = mysql_fetch_field_direct( prepare_meta_result, i );  //返回字段类型
        m_fields.push_back( field->name );
    }

    iRet = mysql_stmt_bind_result( stmt, bind_result );
    if (iRet != 0)
    {
        throw Exception( hander->getHander());
    }

    iRet = mysql_stmt_execute( stmt );
    if (iRet != 0)
    {
        throw Exception( hander->getHander());
    }

    iRet = mysql_stmt_store_result( stmt );      //以便后续的mysql_stmt_fetch()调用能返回缓冲数据
    if (iRet != 0)
    {
        throw Exception( hander->getHander());
    }

    return 0;
}

const std::vector<std::string> &Statement::getFields() const
{
    return m_fields;
}
